#!/usr/bin/python
#-*- coding: utf-8 -*-
'''
Created on 24.06.2012
Modul um VBOs erzeugen und benutzenzu koennen.
@author: ptreb001, ahoeng001
'''
from numpy import array
from OpenGL.arrays import vbo
from GameConfigFile import  *
from obj import OBJ


class VBOHandler(object):
    """vbo Objekte koennen Liste von Zahlen in VBOs wandeln und stellen Methoden fuer den gebrauch in OpenGL bereit"""

    def __init__(self, filename=None, size_of_vertex_coordinates=3):
        """1D Liste points zum Initialisieren moeglich"""
        self.__SIZE_OF_VERTEX_COORDINATES = size_of_vertex_coordinates
        self.__obj = None
        self.__points_lis = None
        self.__structure = None
        self.__length = None
        self.__vbo = None # echtes oglVbo bekommt keine property
        self.__vertex_pointer = None
        self.__normal_pointer = None
        self.__texture_pointer = None
        self.__stride = None 
        
        # moegliche VBO Strukturen
        self.__VT = 'v/t'
        self.__VN = 'v//n'
        self.__VTN = 'v/t/n'
        self.__V = 'v'
        
        if filename==None:
            # benutze hardcoded CubeMapVertices
            self.points_lis = self.get_vertex_and_texture_coordinates(self.get_hardcoded_cube_map_vertices())
            self.structure = self.VTN # FIXME berrechnen
            self.__length = self.SIZE_OF_VERTEX_COORDINATES * len([point for point in self.points_lis])
        else:
            # Lese uebergebene .obj Datei ein
            
            self.__obj = OBJ(filename)            
            self.points_lis = self.obj.faces
            self.structure = self.obj.faces_structure
            self.__length = len(self.obj.faces)
            
        self.__vbo = self._get_gl_vbo()
        
        # schrittweite wann der naechste vertex beginnt, kann variieren je nach indexed faceset
        self.stride = self.compute_stride(self.structure)
    
    def get_vertex_and_texture_coordinates(self,
                                           lis #  [1,-1,1,-1,-1,...] 24x3 Koordinaten
                                       ):
        """Gibt berrechnete Liste von Koordinaten Listen fuer
        eine GL_TEXTURE_CUBE_MAP zueck.
        [1, 2, 3, 4, 5, 6] -> [[1, 2, 3, 1, 2, 3], [4, 5, 6, 4, 5, 6]]"""
        
        # GL_TEXTURE_CUBE_MAP braucht 3 Texturkoordinaten,
        # 3. koordinate ist x,y,z (die selbe wie Vertexkoordinate nehmen)
        ret = [2*lis[i:i+3] for i in range(0, len(lis), 3) ]
        return ret

    def get_hardcoded_cube_map_vertices(self):
        """Gibt Liste mit Vertex-Koordinaten zurueck [1,-1,1,-1,...]"""
        pos = CUBE_SIZE/2
        neg = -CUBE_SIZE/2
        self.vertex_coordinates = [neg, neg, pos, # LEFT / Negative X
                            neg, neg, neg,
                            neg, pos, neg,
                            neg, pos, pos,
                            pos, neg, neg, # RIGHT / Positive X
                            pos, neg, pos,
                            pos, pos, pos,
                            pos, pos, neg,
                            neg, neg, neg, # BACK / Negative Z
                            pos, neg, neg,
                            pos, pos, neg,
                            neg, pos, neg,
                            pos, neg, pos, # FRONT / Positive Z
                            neg, neg, pos,
                            neg, pos, pos,
                            pos, pos, pos,
                            neg, pos, pos, # TOP / Positive Y
                            neg, pos, neg,
                            pos, pos, neg,
                            pos, pos, pos,
                            neg, neg, neg, # BOTTOM / Negative Y
                            neg, neg, pos,
                            pos, neg, pos,
                            pos, neg, neg
                            ]
        return self.vertex_coordinates
#
#    def get_vertices_in_proper_form(self):
#        """Gibt liste fuer VBO nutzung formatiert zurueck"""
#        coordinates = self.get_vertex_coordinates()
#        vertex_and_texture_coordinates = self.get_vertex_and_texture_coordinates(coordinates)
#        return  vertex_and_texture_coordinates

    def get_vertex_pointer(self):
        """Pointer auf 1. Vertex im VBO Speicher"""
        return self.__vbo

    # TODO testen
    def get_normal_pointer(self):
        """Pointer auf 1. Normale im VBO Speicher"""
        if self.structure == self.__VTN:
            step = 2 * self.__SIZE_OF_VERTEX_COORDINATES * 4
        elif self.structure == self.__VN:
            step = self.__SIZE_OF_VERTEX_COORDINATES * 4
        else:
            step = 0
        ret = self.__normal_pointer + step            
        return ret


    def get_texture_pointer(self):
        """Pointer auf 1. Textur im VBO Speicher"""
        return self.vertex_pointer + (self.__SIZE_OF_VERTEX_COORDINATES * 4)    


    def set_vertex_pointer(self, value):
        self.__vertex_pointer = value


    def set_normal_pointer(self, value):
        self.__normal_pointer = value


    def set_texture_pointer(self, value):
        self.__texture_pointer = value


    def get_vtn(self):
        return self.__VTN


    def set_vtn(self, value):
        self.__VTN = value



    def get_points_lis(self):
        return self.__points_lis


    def set_points_lis(self, value):
        self.__points_lis = value


    def get_stride(self):
        return self.__stride


    def set_stride(self, value):
        self.__stride = value


    def get_length(self):
        return self.__length

    def set_structure(self, value):
        self.__structure = value
        
    def get_structure(self):
        return self.__structure


    def get_size_of_vertex_coordinates(self):
        return self.__SIZE_OF_VERTEX_COORDINATES


    def set_size_of_vertex_coordinates(self, value):
        self.__SIZE_OF_VERTEX_COORDINATES = value

    
    def get_obj(self):
        return self.__obj


    def set_obj(self, value):
        self.__obj = value
        
    def _get_gl_vbo(self):
        """Generiert ein OpenGL VBO aus interner Punkteliste"""
        return vbo.VBO(array(self.points_lis, 'f'))
 
    def compute_stride(self, structure):
        """Gibt Schrittweite im VBO zurueck"""        
        stride_skalar = 1
        if structure is self.__VT or self.__VN:
            stride_skalar = 2
        elif structure is self.__VNT:
            stride_skalar = 3
        return stride_skalar * 4 * self.SIZE_OF_VERTEX_COORDINATES 
 
    def __repr__(self):
        output = []
        output.append("Schrittweite (Byte) ab denen neuer Vertex beginnt: %i" % self.stride)
        output.append("Struktur: %s" % self.structure)
        output.append("Gesamtlaenge (alle Elemente): %d" % self.length)
        return '\n'.join(output)

    def unbind(self):
        self.__vbo.unbind()
        

    def bind(self):
        """bindet das oglVbo"""
        self.__vbo.bind()
        
    obj = property(get_obj, set_obj, None, "obj's docstring")
    SIZE_OF_VERTEX_COORDINATES = property(get_size_of_vertex_coordinates, set_size_of_vertex_coordinates, None, "SIZE_OF_VERTEX_COORDINATES's docstring")
    structure = property(get_structure, set_structure, None, "structure's docstring")
    length = property(get_length, None, "Anzahl aller Vertex Koordinaten-Elemente z.B. 3(x,y,z) * 3(tx, ty, tz) * 8Ecken = 72")
    stride = property(get_stride, None, None, "stride's docstring")
    points_lis = property(get_points_lis, None, None, "points_lis's docstring")
    stride = property(get_stride, set_stride, None, "stride's docstring")
    points_lis = property(get_points_lis, set_points_lis, None, "points_lis's docstring")
    VTN = property(get_vtn, set_vtn, None, "VTN's docstring")
    vertex_pointer = property(get_vertex_pointer, set_vertex_pointer, None, "vertex_pointer's docstring")
    normal_pointer = property(get_normal_pointer, set_normal_pointer, None, "normal_pointer's docstring")
    texture_pointer = property(get_texture_pointer, set_texture_pointer, None, "texture_pointer's docstring")
        
if __name__ == "__main__":
    print 'vbo_handler main()'
